/* Copyright (c) 2008, The Visigoth Software Society
 * Copyright (c) 2006, Sun Microsystems Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notices,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name Visigoth Software Society, FreeCC, Sun Microsystems, Inc. 
 *       nor the names of any contributors may be used to endorse or promote 
 *       products derived from this software without specific prior written 
 *       permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.visigoths.freecc.parsegen;

import java.util.*;

import org.visigoths.freecc.Grammar;
import org.visigoths.freecc.FreeCCNode;

import org.visigoths.freecc.parser.FreeCCConstants;
import org.visigoths.freecc.parser.Token;
import org.visigoths.freecc.parser.tree.*;

/**
 * Describes JavaCC productions.
 */

public class NormalProduction extends FreeCCNode {

    private TreeNodeBehavior treeNodeBehavior;
    private ThrowsList throwsList;
    private FormalParams parameterList;
    private String leadingComments;
    /**
     * The RHS of this production. Not used for JavaCodeProduction.
     */
    private Expansion expansion;


    public NormalProduction(Grammar grammar) {
        super(grammar);
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
    
    public ThrowsList getThrowsList() {
        return throwsList;
    }
    
    public void setThrowsList(ThrowsList throwsList) {
        this.throwsList = throwsList;
    }
    
    public FormalParams getParameterList() {
        return parameterList;
    }
    
    public void setParameterList(FormalParams parameterList) {
        this.parameterList = parameterList;
    }
    
    public TreeNodeBehavior getTreeNodeBehavior() {
        return treeNodeBehavior;
    }
    
    public void setTreeNodeBehavior(TreeNodeBehavior treeNodeBehavior) {
        if (grammar.getOptions().getTreeBuildingEnabled()) {
            if (treeNodeBehavior == null) {
                if (!grammar.getOptions().getNodeDefaultVoid()) {
                    if (!grammar.getOptions().getSmartNodeCreation()) {
                        treeNodeBehavior = new TreeNodeBehavior(grammar, this.name, null, false);
                    } else {
                        Expression condition = new Expression(FreeCCConstants.JJTEXPRESSION) {
                            public String getAsString() {
                                return "1";
                            }
                        };
                        treeNodeBehavior = new TreeNodeBehavior(grammar, this.name, condition, true);
                    }
                    treeNodeBehavior.implicit = true;
                }
            }
            this.treeNodeBehavior = treeNodeBehavior;
            if (treeNodeBehavior != null) {
                grammar.addNodeType(treeNodeBehavior.getNodeName());
            }
        }
    }
    

    /**
     * The NonTerminal nodes which refer to this production.
     */
    List<Expansion> parents = new ArrayList<Expansion>();

    /**
     * The access modifier of this production.
     */
    public String accessMod;

    /**
     * The name of the non-terminal of this production.
     */
    private String name;
    
    private ReturnType returnType;

    public Expansion getExpansion() {
        return expansion;
    }
    
    public void setExpansion(Expansion expansion) {
        expansion.parent = this;
        this.expansion = expansion;
    }

    /**
     * This boolean flag is true if this production can expand to empty.
     */
    public boolean emptyPossible = false;

    /**
     * A list of all non-terminals that this one can expand to without having to
     * consume any tokens. Also an index that shows how many pointers exist.
     */
    public NormalProduction[] leftExpansions = new NormalProduction[10];
    public int leIndex = 0;

    /**
     * The following variable is used to maintain state information for the
     * left-recursion determination algorithm: It is initialized to 0, and set
     * to -1 if this node has been visited in a pre-order walk, and then it is
     * set to 1 if the pre-order walk of the whole graph from this node has been
     * traversed. i.e., -1 indicates partially processed, and 1 indicates fully
     * processed.
     */
    int walkStatus = 0;

    protected String eol = System.getProperty("line.separator", "\n");

    protected StringBuilder dumpPrefix(int indent) {
        StringBuilder sb = new StringBuilder(128);
        for (int i = 0; i < indent; i++)
            sb.append("  ");
        return sb;
    }

    protected String getSimpleName() {
        String name = getClass().getName();
        return name.substring(name.lastIndexOf(".") + 1); // strip the package
                                                            // name
    }

    public String getAccessModifier() {
        if (accessMod == null)
            return "";
        return accessMod;
    }

    public ReturnType getReturnType() {
        return returnType;
    }
    
    public void setReturnType(ReturnType returnType) {
        this.returnType = returnType;
    }
    
    public void adjustFirstToken(Token t) {
        this.leadingComments = t.getLeadingComments();
        t.specialToken = null;
    }

    public String getLeadingComments() {
        return leadingComments;
    }
}
